/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package it.coraci.anag.gui.components.basic.gui;

import it.coraci.anag.db.mongo.entities.Attribute;
import it.coraci.anag.gui.components.basic.annotations.GuiParam;
import it.coraci.anag.gui.components.basic.annotations.GuiParamBooleanValue;
import it.coraci.anag.gui.components.basic.annotations.GuiParamFilePath;
import it.coraci.anag.gui.components.basic.annotations.GuiParamMultiValue;
import it.coraci.anag.gui.components.basic.gui.logic.CRUDCentral;
import it.coraci.anag.gui.components.basic.gui.logic.CRUDParametrizablePanel;
import it.coraci.anag.gui.components.basic.gui.logic.CRUDUpdateEntityListener;
import java.beans.Beans;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

/**
 *
 * @author Luca
 */
public class CRUDPanel extends javax.swing.JPanel implements CRUDUpdateEntityListener {

    private boolean editable = false;
    private Object currentEntity = null;
    private Class<?> entityClazz;
    private Map<String, CRUDParametrizablePanel> keyPanel = new HashMap<String, CRUDParametrizablePanel>();

    private String addEntityButtonText;
    private String saveEntityButtonText;
    private String editEntityButtonText;
    private String deleteEntityButtonText;
    private boolean noSQL = false;
    private boolean deleteEnabled = false;

    /**
     * Creates new form CRUDPanel
     */
    public CRUDPanel() {
        initComponents();
        if (!Beans.isDesignTime()) {
            CRUDCentral.getInstance().addCRUDUpdateEntityListener(this);
        }
    }

    public void setToolbarVisible(boolean visible) {
        this.jToolBar_button.setVisible(visible);
    }

    public boolean isDeleteEnabled() {
        return deleteEnabled;
    }

    public void setDeleteEnabled(boolean deleteEnabled) {
        this.deleteEnabled = deleteEnabled;
    }

    public boolean isNoSQL() {
        return noSQL;
    }

    public void setNoSQL(boolean noSQL) {
        this.noSQL = noSQL;
    }

    public String getAddEntityButtonText() {
        return addEntityButtonText;
    }

    public void setAddEntityButtonText(String addEntityButtonText) {
        this.addEntityButtonText = addEntityButtonText;
        this.jButton_add.setText(addEntityButtonText);
    }

    public void clear() {
        Set<String> keySet = keyPanel.keySet();
        for (String key : keySet) {
            this.keyPanel.get(key).clear();
        }
    }

    public String getSaveEntityButtonText() {
        return saveEntityButtonText;
    }

    public void setSaveEntityButtonText(String saveEntityButtonText) {
        this.saveEntityButtonText = saveEntityButtonText;
        this.jButton_saveChanges.setText(saveEntityButtonText);
    }

    public String getEditEntityButtonText() {
        return editEntityButtonText;
    }

    public void setEditEntityButtonText(String editEntityButtonText) {
        this.editEntityButtonText = editEntityButtonText;
        this.jToggleButton_Edit.setText(editEntityButtonText);
    }

    public boolean isEditable() {
        return editable;
    }

    public void setEditable(boolean editable) {
        this.editable = editable;
        Set<String> keySet = this.keyPanel.keySet();
        for (String label : keySet) {
            this.keyPanel.get(label).setEditable(editable);
        }
    }

    public void loadEntity(Object entity) {
        this.currentEntity = entity;
        if (isNoSQL()) {
            this.clear();
//            List<String> keyToRemove = new ArrayList<String>();
//            Set<String> keySet = this.keyPanel.keySet();
//            for (String key : keySet) {
//                CRUDParametrizablePanel panel = this.keyPanel.get(key);
//                if(panel instanceof SimpleMongoParamPanel){
//                    this.remove((SimpleMongoParamPanel)panel);
//                    keyToRemove.add(key);
//                }
//            }
//            for (String kk : keyToRemove) {
//                //removing unused mongo keys
//                this.keyPanel.clear();
//            }
        }
//        prepareForClass(entityClazz);
        Field[] fields = entity.getClass().getDeclaredFields();
        for (Field field : fields) {
//            System.out.println("-------------------");
            System.out.println(" loading field: " + field.getName());
            field.setAccessible(true);
            try {
                if (keyPanel.get(field.getName()) instanceof SimpleOneToManyParamPanel) {
                    ((SimpleOneToManyParamPanel) keyPanel.get(field.getName())).setParentObject(currentEntity);
                }

                if ((field.getAnnotation(OneToMany.class) != null) && (field.getAnnotation(GuiParam.class) != null)) {
                    GuiParam gp = field.getAnnotation(GuiParam.class);
                    if (gp.type() == GuiParam.GuiParamType.ONE_TO_MANY) {
                        this.keyPanel.get(field.getName()).setValue(((List) field.get(entity)));
                    }
                } //                if(field.getAnnotation(GuiParam.class)!= null && (field.getAnnotation(GuiParam.class).type() == GuiParam.GuiParamType.MONGO_SPECIAL)){
                //                    
                //                }
                else if (this.keyPanel.containsKey(field.getName())) {
//                    JOptionPane.showMessageDialog(null, "FIELD NAME: "+field.getName());
                    this.keyPanel.get(field.getName()).setValue(field.get(entity));
                } else {
                    System.out.println("mai visto");
                }
            } catch (IllegalArgumentException ex) {
                Logger.getLogger(CRUDPanel.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                Logger.getLogger(CRUDPanel.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        System.out.println("keySIZE = " + this.keyPanel.size());
    }

    public void prepareForClass(Class<?> clazz) {
        this.entityClazz = clazz;
//        System.out.println("analizing: " + clazz.getCanonicalName());
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
//            System.out.println("field: " + field.getName());
            field.setAccessible(true);
            Annotation[] declaredAnnotations = field.getDeclaredAnnotations();
            for (Annotation annotation : declaredAnnotations) {
                if (annotation instanceof GuiParam) {
                    GuiParam gp = field.getAnnotation(GuiParam.class);
                    Attribute attr = new Attribute(gp.label(), null);
                    CRUDParametrizablePanel panel = null;
                    switch (gp.type()) {
                        case TEXT:
                            if (field.getAnnotation(GuiParamFilePath.class) != null) {
                                GuiParamFilePath ann2 = field.getAnnotation(GuiParamFilePath.class);
                                String pastePath = ann2.pastePath();
                                panel = new SimpleFilePathParamPanel(attr, pastePath);
                            } else {
                                panel = new SimpleTextParamPanel(attr);
                            }
                            jPanel1.add((JPanel) panel);
                            break;
                        case BOOLEAN:
                            if (field.getAnnotation(GuiParamBooleanValue.class) != null) {
                                GuiParamBooleanValue guiParamBooleanValue = field.getAnnotation(GuiParamBooleanValue.class);
                                panel = new SimpleBooleanMultiParamPanel(attr, guiParamBooleanValue.trueValue(), guiParamBooleanValue.falseValue());
                            } else if (field.getAnnotation(GuiParamMultiValue.class) != null) {
                                GuiParamMultiValue gg = field.getAnnotation(GuiParamMultiValue.class);
                                panel = new SimpleMultiParamPanel(attr, gg.multivalues());
                            } else {
//                                System.out.println(" ---- no anno");
                                panel = new SimpleBooleanParamPanel(attr);
                            }
                            jPanel1.add((JPanel) panel);
                            break;
                        case DATE:
                            panel = new SimpleDateParamPanel(attr);
                            jPanel1.add((JPanel) panel);
                            break;
                        case MONGO_SPECIAL:
                            List<Attribute> attrs;
                            if (currentEntity != null) {
                                try {

                                    attrs = (List<Attribute>) field.get(currentEntity);
                                    panel = new SimpleMongoParamPanel(attrs);
                                    jPanel1.add((JPanel) panel);
                                } catch (IllegalArgumentException ex) {
                                    Logger.getLogger(CRUDPanel.class.getName()).log(Level.SEVERE, null, ex);
                                } catch (IllegalAccessException ex) {
                                    Logger.getLogger(CRUDPanel.class.getName()).log(Level.SEVERE, null, ex);
                                }
                            }

                            break;
                        case ONE_TO_MANY:
                            System.out.println("FIELD : " + field.getName());
//                                panel = new SimpleOneToManyParamPanel(gp.label(), ((List<Object>) field.get(currentEntity)).toArray());
                            panel = new SimpleOneToManyParamPanel(gp.label(), new Object[]{});
                            ParameterizedType stringListType = (ParameterizedType) field.getGenericType();
                            Class<?> newClazzType = (Class<?>) stringListType.getActualTypeArguments()[0];
                            ((SimpleOneToManyParamPanel) panel).setNewEntityClazz(newClazzType);
                            ((SimpleOneToManyParamPanel) panel).setParentObject(currentEntity);
                            ((SimpleOneToManyParamPanel) panel).setListFieldName(field.getName());
                            jPanel1.add((JPanel) panel);
                            break;
                        case ONE_TO_ONE:
                            System.out.println("FIELD : " + field.getName());
                            List<?> entities = CRUDCentral.getInstance().findAllEntities(field.getType());
                            JOptionPane.showMessageDialog(null, "GRA GRA");
                            panel = new SimpleOneToOneParamPanel(gp.label(), entities.toArray());
//                            ParameterizedType stringListType = (ParameterizedType) field.getGenericType();
//                            Class<?> newClazzType = (Class<?>) stringListType.getActualTypeArguments()[0];
                            ((SimpleOneToOneParamPanel) panel).setNewEntityClazz(field.getType());
//                            ((SimpleOneToManyParamPanel) panel).setParentObject(currentEntity);
//                            ((SimpleOneToManyParamPanel) panel).setListFieldName(field.getName());
                            jPanel1.add((JPanel) panel);
                            break;
                    }
                    if (panel != null) {
                        this.keyPanel.put(field.getName(), panel);
                        panel.setEditable(editable);
                    }
                } else if (annotation instanceof GuiParamBooleanValue) {
//                    System.out.println("  ------- ABABUAHUSHduahsdu");
                }
            }

        }
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jToolBar_button = new javax.swing.JToolBar();
        jButton_add = new javax.swing.JButton();
        jToggleButton_Edit = new javax.swing.JToggleButton();
        jButton_saveChanges = new javax.swing.JButton();
        jButton_Delete = new javax.swing.JButton();
        jPanel1 = new javax.swing.JPanel();

        jToolBar_button.setFloatable(false);
        jToolBar_button.setRollover(true);

        jButton_add.setText("add");
        jButton_add.setFocusable(false);
        jButton_add.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jButton_add.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        jButton_add.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton_addActionPerformed(evt);
            }
        });
        jToolBar_button.add(jButton_add);

        jToggleButton_Edit.setText("Edit");
        jToggleButton_Edit.setFocusable(false);
        jToggleButton_Edit.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jToggleButton_Edit.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        jToggleButton_Edit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jToggleButton_EditActionPerformed(evt);
            }
        });
        jToolBar_button.add(jToggleButton_Edit);

        jButton_saveChanges.setText("save changes");
        jButton_saveChanges.setEnabled(false);
        jButton_saveChanges.setFocusable(false);
        jButton_saveChanges.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jButton_saveChanges.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        jButton_saveChanges.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton_saveChangesActionPerformed(evt);
            }
        });
        jToolBar_button.add(jButton_saveChanges);

        jButton_Delete.setText("delete");
        jButton_Delete.setFocusable(false);
        jButton_Delete.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        jButton_Delete.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        jToolBar_button.add(jButton_Delete);

        jPanel1.setBackground(new java.awt.Color(204, 102, 0));
        jPanel1.setLayout(new javax.swing.BoxLayout(jPanel1, javax.swing.BoxLayout.Y_AXIS));

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jToolBar_button, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
            .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addComponent(jToolBar_button, javax.swing.GroupLayout.PREFERRED_SIZE, 34, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 219, Short.MAX_VALUE))
        );
    }// </editor-fold>//GEN-END:initComponents

    private void jToggleButton_EditActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jToggleButton_EditActionPerformed
        this.setEditable(this.jToggleButton_Edit.isSelected());
        this.jPanel1.invalidate();
        this.jPanel1.revalidate();
        this.jPanel1.repaint();
        this.jButton_saveChanges.setEnabled(this.jToggleButton_Edit.isSelected());


    }//GEN-LAST:event_jToggleButton_EditActionPerformed

    private void jButton_addActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton_addActionPerformed
        if (entityClazz != null) {
            AddNewEntityFrame addNew = new AddNewEntityFrame(entityClazz);
            addNew.setLocationRelativeTo(this);
            addNew.setTitle("Add new Entity");
            addNew.setVisible(true);
        }

    }//GEN-LAST:event_jButton_addActionPerformed

    private void jButton_saveChangesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton_saveChangesActionPerformed
        this.jToggleButton_Edit.setSelected(false);
        this.jButton_saveChanges.setEnabled(false);
        Object idToUpdate = null;
        if (this.currentEntity != null) {
            try {
                Object entity = this.currentEntity.getClass().getConstructor().newInstance();
                for (String fieldName : this.keyPanel.keySet()) {
                    Field declaredField = entity.getClass().getDeclaredField(fieldName);
                    declaredField.setAccessible(true);
                    if (keyPanel.get(fieldName).getValue() != null) {
                        declaredField.set(entity, keyPanel.get(fieldName).getValue());
                    } else {
//                    System.out.println("field: "+);
                    }
                }
                //copying ID:
                Field[] declaredFields = this.currentEntity.getClass().getDeclaredFields();
                for (Field field : declaredFields) {
                    Id idAnnotation = field.getAnnotation(Id.class);
                    if (idAnnotation != null) {
                        System.out.println("ID FOUND");
                        field.setAccessible(true);
                        Object id = field.get(this.currentEntity);
                        idToUpdate = id;
                        Field[] targetFields = entity.getClass().getDeclaredFields();
                        for (Field ff : targetFields) {
                            ff.setAccessible(true);
                            Id targetIdAnnotation = ff.getAnnotation(Id.class);
                            if (targetIdAnnotation != null) {
                                ff.set(entity, id);
                            }
                        }
                    }
                }

                CRUDCentral.getInstance().updateEntity(entity);
                if (idToUpdate != null) {
                    System.out.println("id non null");
                    CRUDCentral.getInstance().updateMe(entityClazz, idToUpdate);
                }
                JOptionPane.showMessageDialog(null, "The entity has been correctly updated!");
            } catch (NoSuchMethodException ex) {
                Logger.getLogger(CRUDPanel.class.getName()).log(Level.SEVERE, null, ex);
            } catch (SecurityException ex) {
                Logger.getLogger(CRUDPanel.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InstantiationException ex) {
                Logger.getLogger(CRUDPanel.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                Logger.getLogger(CRUDPanel.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IllegalArgumentException ex) {
                Logger.getLogger(CRUDPanel.class.getName()).log(Level.SEVERE, null, ex);
            } catch (InvocationTargetException ex) {
                Logger.getLogger(CRUDPanel.class.getName()).log(Level.SEVERE, null, ex);
            } catch (NoSuchFieldException ex) {
                Logger.getLogger(CRUDPanel.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }//GEN-LAST:event_jButton_saveChangesActionPerformed

    public void addTextParam(String param) {
        Attribute attr = new Attribute(param, null);
        CRUDParametrizablePanel panel = new SimpleTextParamPanel(attr);
        jPanel1.add((JPanel) panel);
        this.keyPanel.put(param, panel);
        panel.setEditable(editable);
    }


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton jButton_Delete;
    private javax.swing.JButton jButton_add;
    private javax.swing.JButton jButton_saveChanges;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JToggleButton jToggleButton_Edit;
    private javax.swing.JToolBar jToolBar_button;
    // End of variables declaration//GEN-END:variables

    @Override
    public void updateThisEntity(Class<?> entityClazz, Object id) {

    }

    @Override
    public void entitySelected(Object entity) {
        if (entity != null && this.entityClazz != null) {
            if (entity.getClass().getCanonicalName().equals(this.entityClazz.getCanonicalName())) {
                this.clear();
                this.loadEntity(entity);
            }
        }
    }

    @Override
    public void newEntity(Object entityClazz) {

    }

}
